////TODO: AdaptiveThresholding, check if result is ok

//using System;
//using System.Diagnostics;
//using System.Collections;
//using System.Collections.Generic;
//using System.Drawing;
//using System.Drawing.Imaging;
//using System.Windows.Forms;

//namespace LowLevelGraphics.Filter
//{
//    /// <summary>
//    /// 
//    /// </summary>
//    public enum THRESHOLDING_MODE
//    {
//        /// <summary>
//        /// Use median
//        /// </summary>
//        MEDIAN,
        
//        /// <summary>
//        /// Use mean
//        /// </summary>        
//        MEAN,
        
//        /// <summary>
//        /// Use min/max
//        /// </summary>
//        MIN_MAX, 

//        /// <summary>
//        /// Use integral Image
//        /// </summary>
//        INTEGRAL_IMAGE, 

//        /// <summary>
//        /// Use convergence, i.e. use automatic thresholding then use threshold
//        /// 
//        /// </summary>
//        CONVERGENCE,

//        /// <summary>
//        /// Exactly like CONVERGENCE, BUT only once determines new threshold
//        /// </summary>
//        AUTOTHRESHOLD_ONCE,

//        /// <summary>
//        /// Own derived method
//        /// </summary>
//        OWN_METHOD,

//        /// <summary>
//        /// If same threshold appeared twice
//        /// </summary>
//        SAME_THRESHOLD_TWICE
//    }

//    /// <summary>
//    /// AdaptiveThreshold is an algorithm to apply adaptive thresholding to an image.
//    /// Choose between min/max, median or mean
//    /// </summary>
//    public class AdaptiveThresholding : Threshold
//    {
//        //the width and height of this image in pixels
//        protected int m_nWidth = 0, m_nHeight = 0;
//        protected Ranking m_Ranking = new Ranking();

//        /// <summary>
//        /// 
//        /// </summary>
//        protected THRESHOLDING_MODE M_MODE = THRESHOLDING_MODE.MEAN;
//        /// <summary>
//        /// 
//        /// </summary>
//        protected int m_nWindowSize = 7;
//        protected int m_nConstant = 7;
//        protected bool m_bUseRankingAfterwards = false;

//        /// <summary>
//        /// Default constructor using min/max mode with a window size of 7
//        /// </summary>
//        public AdaptiveThresholding()
//        {
//        }

//        /// <summary>
//        /// Specify thresholding mode directly
//        /// </summary>
//        /// <param name="_MODE"></param>
//        public AdaptiveThresholding(THRESHOLDING_MODE _MODE)
//            : this(_MODE, 8, 0)
//        {
//        }

//        /// <summary>
//        /// Specify thresholding mode, window size and constant directly
//        /// </summary>
//        /// <param name="_MODE"></param>
//        /// <param name="_nWindowSize"></param>
//        /// <param name="_nConstant"></param>
//        public AdaptiveThresholding(THRESHOLDING_MODE _MODE, int _nWindowSize, int _nConstant)
//        {
//            M_MODE = _MODE;
//            m_nWindowSize = _nWindowSize;
//            m_nConstant = _nConstant;
//        }

//        /// <summary>
//        /// Use this to create a copy
//        /// </summary>
//        /// <param name="_adaptiveThresholding"></param>
//        internal AdaptiveThresholding(AdaptiveThresholding _adaptiveThresholding)
//        {
//            this.M_MODE = _adaptiveThresholding.M_MODE;
//            this.m_nWindowSize = _adaptiveThresholding.m_nWindowSize;
//            this.m_nConstant = _adaptiveThresholding.m_nConstant;
//            this.m_bUseRankingAfterwards = _adaptiveThresholding.m_bUseRankingAfterwards;
//        }

//        /// <summary>
//        /// thresholding mode
//        /// </summary>
//        public THRESHOLDING_MODE ThresholdingMode
//        {
//            get { return M_MODE; }
//            set { M_MODE = value; }
//        }

//        /// <summary>
//        /// kernel filter size
//        /// </summary>
//        public int WindowSize
//        {
//            get { return m_nWindowSize; }
//            set { m_nWindowSize = value; }
//        }

//        /// <summary>
//        /// Set or read the constant
//        /// </summary>
//        public int Constant
//        {
//            get { return m_nConstant; }
//            set { m_nConstant = value; }
//        }

//        /// <summary>
//        /// Set or read if a ranking filter will be used afterwards
//        /// </summary>
//        public bool UseRankingAfterwards
//        {
//            get { return m_bUseRankingAfterwards; }
//            set { m_bUseRankingAfterwards = value; }
//        }

//        /// <summary>
//        /// Executes this filter
//        /// </summary>
//        /// <param name="_bitmap"></param>
//        /// <returns></returns>
//        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
//        {
//            int nWidth = _bitmap.Width;
//            int nHeight = _bitmap.Height;

//            int nThresholdStart = -1;
//            switch (M_MODE)
//            {
//                case THRESHOLDING_MODE.MEAN:
//                    MeanThreshold(_bitmap, nWidth, nHeight,m_nWindowSize, m_nConstant);
//                    break;

//                case THRESHOLDING_MODE.MEDIAN:
//                    MedianThreshold(_bitmap, nWidth, nHeight, m_nWindowSize, m_nConstant);
//                    break;

//                case THRESHOLDING_MODE.MIN_MAX:
//                    MeanMaximumMinimumThreshold(_bitmap, nWidth, nHeight, m_nWindowSize, m_nConstant);
//                    break;

//                case THRESHOLDING_MODE.INTEGRAL_IMAGE:
//                    IntegralImageThreshold(_bitmap, nWidth, nHeight, m_nWindowSize, m_nConstant);
//                    break;

//                case THRESHOLDING_MODE.CONVERGENCE:
//                    nThresholdStart = new Random(DateTime.Now.Millisecond).Next(0,255);
//                    while (nThresholdStart != GetThreshold(_bitmap))
//                    {
//                        nThresholdStart = GetThreshold(_bitmap);
//                        Debug.WriteLine(nThresholdStart);
//                    }
//                    new Threshold2().Execute(_bitmap);
//                    break;

//                case THRESHOLDING_MODE.AUTOTHRESHOLD_ONCE:
//                    nThresholdStart = new Random(DateTime.Now.Millisecond).Next(0,255);
//                    nThresholdStart = GetThreshold(_bitmap);
//                    new Threshold2().Execute(_bitmap);
//                    break;

//                case THRESHOLDING_MODE.SAME_THRESHOLD_TWICE:
//                    nThresholdStart = new Random(DateTime.Now.Millisecond).Next(0,255);
//                    SortedList<int, int> aFound = new SortedList<int, int>();
//                    while (nThresholdStart != GetThreshold(_bitmap))
//                    {
//                        nThresholdStart = GetThreshold(_bitmap);
//                        if (!aFound.ContainsKey(nThresholdStart))
//                        {
//                            aFound.Add(nThresholdStart, 0);
//                        }
//                        else
//                        {
//                            aFound[nThresholdStart]++;
//                            break;
//                        }
//                        Debug.WriteLine(nThresholdStart);
//                    }
//                    new Threshold2().Execute(_bitmap);
//                    break;

//                case THRESHOLDING_MODE.OWN_METHOD:
//                    int nThreshold = GetThreshold(_bitmap);
//                    int y = 0;
//                    int x = 0;
//                    for (y = 0; y < nHeight; y++)
//                    {
//                        for (x = m_nWindowSize; x < nWidth-m_nWindowSize; x++)
//                        {
//                            int nValue = 0;
//                            for (int i = 0; i < m_nWindowSize; i++)
//                            {
//                                nValue += _bitmap.GetGrayPixelValue(x + i, y);
//                            }
//                            _bitmap.SetPixel(x, y, (nValue / m_nWindowSize) > nThreshold ? m_ColorForeground : m_ColorBackground);
//                        }
//                    }
//                    break;
//            }
            
//            if (m_bUseRankingAfterwards)
//            {
//                m_Ranking.Execute(_bitmap);
//            }

//            return _bitmap;
//        }

//        /// <summary>
//        /// 	<param name="_bitmap">pixel array representing image to be thresholded</param>
//        /// 	<param name="_nWidth">width of the image in pixels</param>
//        /// 	<param name="_nHeight">height of the image in pixels</param>
//        /// 	<param name="_nSize">the size of the neigbourhood used in finding the threshold</param>
//        /// 	<param name="_nConstant">the constant value subtracted from the mean</param>
//        /// </summary>
//        /// <param name="_bitmap">The _bitmap.</param>
//        /// <param name="_nWidth">Width of the _n.</param>
//        /// <param name="_nHeight">Height of the _n.</param>
//        /// <param name="_nSize">Size of the _n.</param>
//        /// <param name="_nConstant">The _ constant.</param>
//        private void MeanThreshold(UnsafeBitmap _bitmap, int _nWidth, int _nHeight, int _nSize, int _nConstant)
//        {
//            m_nWidth = _nWidth;
//            m_nHeight = _nHeight;
//            int nMean = 0;
//            int nCount = 0;

//            UnsafeBitmap bitmap = _bitmap;
//            //Now find the sum of values in the size X size neigbourhood 

//            Color color = Color.Transparent;
            
//            int y = 0;
//            int x = 0;
//            int k = 0;
//            int l = 0;

//            int nSizeHalf = _nSize / 2;
//            for (y = 0; y < m_nHeight; y++)
//            {
//                for (x = 0; x < m_nWidth; x++)
//                {
//                    nMean = 0;
//                    nCount = 0;
//                    //TODO: AdaptiveThresholding, MeanThreshold, speedup
//                    //Check the local neighbourhood
//                    for (k = 0; k < _nSize; k++)
//                    {
//                        for (l = 0; l < _nSize; l++)
//                        {
//                            int nTempX = x - nSizeHalf + k;
//                            int nTempY = y - nSizeHalf + l;
//                            if (nTempX > m_nWidth || nTempX < 0 || nTempY > m_nHeight || nTempY < 0) continue;
//                            color = bitmap.GetPixel(nTempX, nTempY);
//                            nMean += ColorFunctions.ToIntRGB(color);
//                            nCount++;
//                        }
//                    }

//                    //Find the mean value
//                    if ((nMean / nCount) != 0)
//                    {
//                        nMean = (int)(nMean / nCount) - _nConstant;
//                    }

//                    //Threshold below/above the mean
//                    bitmap.SetPixel(x, y, ColorFunctions.ToIntRGB(color) > nMean ? m_ColorForeground : m_ColorBackground);
//                }
//            }
//        }

//        /// <summary>
//        /// Applies the adaptive thresholding operator to the specified image array
//        /// using the median function to find the threshold value
//        /// </summary>
//        /// <param name="_bitmap">pixel array representing image to be thresholded</param>
//        /// <param name="_nWidth">width of the image in pixels</param>
//        /// <param name="_nHeight">height of the image in pixels</param>
//        /// <param name="_nSize">the size of the neigbourhood used in finding the threshold</param>
//        /// <param name="con">the constant value subtracted from the median</param>
//        /// <returns></returns>
//        public void MedianThreshold(UnsafeBitmap _bitmap, int _nWidth, int _nHeight, int _nSize,
//                        int con)
//        {
//            m_nWidth = _nWidth;
//            m_nHeight = _nHeight;
//            int nMedian = 0;
//            int[] aValue = new int[_nSize * _nSize];
//            int nCount = 0;

//            UnsafeBitmap bitmap = _bitmap;
//            //Now find the values in the size X size neigbourhood 

//            int y = 0;
//            int x = 0;
//            int k = 0;
//            int l = 0;
//            int nDX = 0;
//            int nDY = 0;

//            int nHalfSize = _nSize / 2;
//            int nSizeSquare = _nSize * _nSize;
//            //Now find the values in the size X size neigbourhood 
//            for (y = 0; y < m_nHeight; y++)
//            {
//                for (x = 0; x < m_nWidth; x++)
//                {
//                    nMedian = 0;
//                    nCount = 0;
//                    aValue = new int[nSizeSquare];
//                    //Check the local neighbourhood
//                    //TODO: median threshold, AdaptiveThresholding, speed up
//                    for (k = 0; k < _nSize; k++)
//                    {
//                        for (l = 0; l < _nSize; l++)
//                        {
//                            nDX = x - nHalfSize + k;
//                            nDY = y - nHalfSize + l;
//                            if (nDX < 0 || nDY < 0 || nDX > m_nWidth - 1 || nDY > m_nHeight - 1)
//                            {
//                                continue;
//                            }

//                            aValue[nCount] = ColorFunctions.ToIntRGB(bitmap.GetPixel(nDX, nDY));
//                            nCount++;
//                        }
//                        //If out of bounds then ignore pixel
//                    }
//                    //Find the median value

//                    //First Sort the array
//                    Array.Sort(aValue);

//                    //Then select the median
//                    nCount /= 2;
//                    nMedian = aValue[nCount] - con;

//                    //Threshold below/above the median
//                    bitmap.SetPixel(x,y, ColorFunctions.ToIntRGB(bitmap.GetPixel(x, y)) >= nMedian ? m_ColorForeground : m_ColorBackground);
//                }
//            }
//        }

//        /// <summary>
//        /// Applies the adaptive thresholding operator to the specified image array
//        /// using the mean of max and min function to find the threshold value
//        /// </summary>
//        /// <param name="_bitmap">The _bitmap.</param>
//        /// <param name="_nWidth">Width of the _n.</param>
//        /// <param name="_nHeight">Height of the _n.</param>
//        /// <param name="_nSize">Size of the _n.</param>
//        /// <param name="_nCon">The _n con.</param>
//        public void MeanMaximumMinimumThreshold(UnsafeBitmap _bitmap, int _nWidth, int _nHeight, int _nSize, int _nCon)
//        {
//            m_nWidth = _nWidth;
//            m_nHeight = _nHeight;
//            int nMean = 0;
//            int nMax = 0, nMin = 0;
//            int[] values = new int[_nSize * _nSize];
//            int[,] tmp_2d = new int[m_nWidth, m_nHeight];

//            int nTemp = 0;

//            UnsafeBitmap bitmap = _bitmap;
//            //Now find the max and min of values in the size X size neigbourhood 

//            int y = 0;
//            int x = 0;
//            int k = 0;
//            int l = 0;
//            int nDX = 0;
//            int nDY = 0;

//            int nCount = 0;
//            int nHalfSize = _nSize / 2;
//            Color color = Color.Transparent;
//            for (y = 0; y < m_nHeight; y++)
//            {
//                for (x = 0; x < m_nWidth; x++)
//                {
//                    nMean = 0;
//                    color = bitmap.GetPixel(x, y);
//                    nMax = ColorFunctions.ToIntRGB(color);
//                    nMin = ColorFunctions.ToIntRGB(color);
//                    //Check the local neighbourhood
//                    for (k = 0; k < _nSize; k++)
//                    {
//                        for (l = 0; l < _nSize; l++)
//                        {
//                            nDX = x - nHalfSize + k;
//                            nDY = y - nHalfSize + l;

//                            if (nDX < 0 || nDY < 0 || nDX > m_nWidth - 1 || nDY > m_nHeight - 1)
//                            {
//                                nCount++;
//                                continue;
//                            }

//                            //nTemp = ColorFunctions.ToIntRGB(bitmap.GetPixel(nDX, nDY));
//                            if (nTemp > nMax)
//                            {
//                                nMax = nTemp;
//                            }
//                            if (nTemp < nMin)
//                            {
//                                nMin = nTemp;
//                            }
//                        }
//                    }

//                    //Find the mean value

//                    nTemp = nMax + nMin;
//                    nTemp /= 2;
//                    nMean = nTemp - _nCon;

//                    bitmap.SetPixel(x, y, ColorFunctions.ToIntRGB(color) >= nMean ? m_ColorForeground : m_ColorBackground);
//                    //Threshold below the mean
//                }
//            }
//        }

//        public void IntegralImageThreshold(UnsafeBitmap @in, int _nWidth, int _nHeight, int _nWindowSize, int _nConstant)
//        {
//            UnsafeBitmap intImg = (UnsafeBitmap)@in.Clone();
//            int sum = 0;
//            for(int i = 0; i <_nWidth; i++)
//            {
//                sum = 0;
//                for(int j = 0;j <_nHeight; j++)
//                {
//                    sum = sum + ColorFunctions.ToIntRGB(@in[i, j]);
//                    if (i == 0) 
//                    {
//                        intImg[i, j] =  Color.FromArgb(sum);
//                    }
//                    else
//                    {
//                        //intImg[i, j]=  Color.FromArgb(ColorFunctions.ToIntRGB(intImg[i-1, j]) + sum);
//                    }
//                }
//            }

//            UnsafeBitmap @out = (UnsafeBitmap)@in.Clone();
//            int s = 0;
//            sum = 0;
//            int x1 = 0;
//            int x2 = 0;
//            int y1 = 0;
//            int y2 = 0;
//            int count = 0;
//            int t = 0;
//            for(int i = 0; i< _nWidth;i++)
//            {
//                for(int j = 0; j<_nHeight;j++)
//                {
//                    x1 = i - s/2; //{border checking is not shown};
//                    x2 = i + s/2;
//                    y1 = j - s/2;
//                    y2 = j+s/2;
//                    count = (x2 - x1) * (y2 - y1);
//                    sum = ColorFunctions.ToIntRGB(intImg[x2,y2]) - ColorFunctions.ToIntRGB(intImg[x2,y1-1]) - ColorFunctions.ToIntRGB(intImg[x1-1,y2]) + ColorFunctions.ToIntRGB(intImg[x1-1,y1-1]);
//                    bool bTest = (ColorFunctions.ToIntRGB(@in[i, j]) * count) <= ( sum * (100 - t) / 100);
//                    if (bTest)
//                    {
//                        @out[i, j] = Color.Black;
//                    }
//                    //else
//                    {
//                        @out[i, j] = Color.White;
//                    }
//                }
//            }
//        }

//        /// <summary>
//        /// Clones this filter
//        /// </summary>
//        /// <returns></returns>
//        public override object Clone()
//        {
//            return new AdaptiveThresholding(this);
//        }
//    }
//}